package pers.cl.dubbo.mvc;

import com.alibaba.fastjson.JSON;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.util.CharsetUtil;
import org.springframework.context.ApplicationContext;
import pers.cl.dubbo.mvc.annotation.Controller;
import pers.cl.dubbo.mvc.annotation.RequestMapping;
import pers.cl.dubbo.mvc.enums.RequestMethod;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenlei
 * @date 2020/1/14
 * @description
 **/
public class DispatchServlet {

    public DispatchServlet(ApplicationContext context) {
        initStrategies(context);
    }

    private List<HandlerMapping> handlerMappings;

    public String doDispatch(FullHttpRequest request, FullHttpResponse response) throws Exception{
        HandlerExecutionChain mappedHandler = null;
        //todo 检查是否文件上传
        checkMultipart(request);
        //todo 获取handler
        mappedHandler = getMappedHandler(request);
        HandlerMapping handlerMapping = getHandlerMapping(request);
        if (handlerMapping == null) {
            throw new Exception("No such method");
        }
        Parameter parameter = handlerMapping.getParameter()[0];
        Class<?> clazz = parameter.getType();
        String body = request.content().toString(CharsetUtil.UTF_8);
        Object o = JSON.parseObject(body, clazz);
        Object result = handlerMapping.getMethod().invoke(handlerMapping.getBean(),o);
        if (result instanceof String) {
            return (String) result;
        }
        return JSON.toJSONString(result);
    }

    //根据路由获取需要执行的方法
    private HandlerMapping getHandlerMapping(FullHttpRequest request) throws Exception {
        String uri = request.uri();
        HttpMethod httpMethod = request.method();
        for (HandlerMapping handlerMapping : handlerMappings) {
            RequestMethod [] requestMethods = handlerMapping.getMethodMapping().method();
            RequestMapping requestMapping = handlerMapping.getRequestMapping();
            String value = "";
            if (requestMapping != null) {
                value = requestMapping.value();
            }
            //找到匹配的url
            if(!uri.startsWith(value)){
                continue;
            }
            String methodUri = uri.substring(value.length());
            //匹配方法
            if (!methodUri.startsWith(handlerMapping.getMethodMapping().value())) {
                continue;
            }
            //匹配方法类型
            for (RequestMethod requestMethod : requestMethods) {
                if(!requestMethod.equals(httpMethod.name())){
                    throw new Exception(uri+"不支持该方法");
                }
            }
            return handlerMapping;
        }
        return null;
    }

    private HandlerExecutionChain getMappedHandler(FullHttpRequest request) {

        return null;
    }

    private void checkMultipart(FullHttpRequest request) {

    }

    //初始化 spring DispatcherServlet这个类初始化了这些，我这里只初始化handlerMapping
    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

    private void initMultipartResolver(ApplicationContext context) {

    }

    private void initLocaleResolver(ApplicationContext context) {

    }

    private void initThemeResolver(ApplicationContext context) {

    }

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = new ArrayList<>();
        String [] beanNames = context.getBeanNamesForAnnotation(Controller.class);
        for (String beanName : beanNames) {
            Object o = context.getBean(beanName);
            Method[] methods = o.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    HandlerMapping handlerMapping = new HandlerMapping();
                    handlerMapping.setRequestMapping(o.getClass().getAnnotation(RequestMapping.class));
                    handlerMapping.setMethodMapping(method.getDeclaredAnnotation(RequestMapping.class));
                    handlerMapping.setBean(o);
                    handlerMapping.setBeanType(o.getClass());
                    handlerMapping.setMethod(method);
                    handlerMapping.setParameter(method.getParameters());
                    handlerMappings.add(handlerMapping);
                }

            }

        }

    }

    private void initHandlerAdapters(ApplicationContext context) {

    }

    private void initHandlerExceptionResolvers(ApplicationContext context) {

    }

    private void initRequestToViewNameTranslator(ApplicationContext context) {

    }

    private void initViewResolvers(ApplicationContext context) {
    }

    private void initFlashMapManager(ApplicationContext context) {
    }
}
